export default class BitmapText extends Laya.Sprite {


    // constructor:
    /**
     * Displays text using bitmap glyphs defined in a sprite sheet. Multi-line text is supported
     * using new line characters, but automatic wrapping is not supported. See the 
     * {{#crossLink "BitmapText/spriteSheet:property"}}{{/crossLink}}
     * property for more information on defining glyphs.
     * 
     * <strong>Important:</strong> BitmapText extends Container, but is not designed to be used as one.
     * As such, methods like addChild and removeChild are disabled.
     * @class BitmapText
     * @extends DisplayObject
     * @param {String} [text=""] The text to display.
     * @param {SpriteSheet} [spriteSheet=null] The spritesheet that defines the character glyphs.
     * @constructor
     **/
    constructor(text, prefix) {
        super();


        // public properties:
        /**
         * The text to display.
         * @property text
         * @type String
         * @default ""
         **/
        this.text = text || "";

        /**
         * 资源前置
         * @property prefix
         * @type String
         * @default null
         **/
        this.prefix = prefix;
        Laya.Loader.textureMap;

        /**
         * The height of each line of text. If 0, then it will use a line height calculated
         * by checking for the height of the "1", "T", or "L" character (in that order). If
         * those characters are not defined, it will use the height of the first frame of the
         * sprite sheet.
         * @property lineHeight
         * @type Number
         * @default 0
         **/
        this.lineHeight = 0;

        /**
         * This spacing (in pixels) will be added after each character in the output.
         * @property letterSpacing
         * @type Number
         * @default 0
         **/
        this.letterSpacing = 1;

        /**
         * If a space character is not defined in the sprite sheet, then empty pixels equal to
         * spaceWidth will be inserted instead. If 0, then it will use a value calculated
         * by checking for the width of the "1", "l", "E", or "A" character (in that order). If
         * those characters are not defined, it will use the width of the first frame of the
         * sprite sheet.
         * @property spaceWidth
         * @type Number
         * @default 0
         **/
        this.spaceWidth = 1;


        // private properties:
        /**
         * @property _oldProps
         * @type Object
         * @protected
         **/
        this._oldProps = {
            text: 0,
            spriteSheet: 0,
            lineHeight: 0,
            letterSpacing: 0,
            spaceWidth: 0
        };
    }

    /**
     * @method _drawText
     * @protected
     **/
    _updateText() {
        var x = 0,
            y = 0,
            o = this._oldProps,
            change = false,
            spaceW = this.spaceWidth,
            lineH = this.lineHeight,
            prefix = this.prefix;
        var pool = BitmapText._spritePool,
            numKids = this.numChildren,
            sprite;

        for (var n in o) {
            if (o[n] != this[n]) {
                o[n] = this[n];
                change = true;
            }
        }
        if (!change) {
            return;
        }
        
        while (numKids > 0) {
            // faster than removeChild.
            sprite = this.removeChildAt(0);
            pool.push(sprite);
            numKids--;
        }

        // var hasSpace = !!this._getFrame(" ",prefix);
        // if (!hasSpace && !spaceW) {
        if (!spaceW) {
            spaceW = this._getSpaceWidth(prefix);
        }
        var findLineH = false;

        for (var i = 0, l = this.text.length; i < l; i++) {
            var character = this.text.charAt(i);
            if (character == " ") {
                x += spaceW;
                continue;
            } else if (character == "\n" || character == "\r") {
                if (character == "\r" && this.text.charAt(i + 1) == "\n") {
                    i++;
                } // crlf
                
                if (!findLineH && !lineH) {
                    findLineH = true;
                    lineH = this._getLineHeight(prefix);
                }
                x = 0;
                y += lineH;
                continue;
            }
            var texture = this._getFrame(character,prefix);
            if (texture == null) {
                continue;
            }
            
            // if (childIndex < numKids) {
            //     sprite = kids[childIndex];
            // } else {
            //     kids.push(sprite = pool.length ? pool.pop() : new Laya.Sprite());
            //     this.addChild(sprite);
            //     numKids++;
            // }
            // sprite.spriteSheet = ss;
            // sprite.gotoAndStop(index);
            sprite = pool.length>0?pool.pop() : new Laya.Sprite();
            sprite.texture = texture;
            sprite.x = x;
            sprite.y = y;
            this.addChild(sprite);
            

            x += sprite.getBounds().width + this.letterSpacing;
        }
        
        if (pool.length > BitmapText.maxPoolSize) {
            pool.length = BitmapText.maxPoolSize;
        }
        // this.reCache();
        // this.cacheAs = "bitmap";
    }

    // /**
    //  * @method _getFrameIndex
    //  * @param {String} character
    //  * @param {String} prefix
    //  * @return {Number}
    //  * @protected
    //  **/
    // _getFrameIndex(character, prefix) {
    //     var c, o = prefix.getAnimation(character);
    //     if (!o) {
    //         (character != (c = character.toUpperCase())) || (character != (c = character.toLowerCase())) || (c = null);
    //         if (c) {
    //             o = prefix.getAnimation(c);
    //         }
    //     }
    //     return o && o.frames[0];
    // };

    /**
     * @method _getFrame
     * @param {String} character
     * @param {SpriteSheet} prefix
     * @return {Object}
     * @protected
     **/
    _getFrame(character, prefix) {
        var charStr = "abcdefghijklmnopqrstuvwxyz1234567890!-./:%";
        var map = Laya.Loader.textureMap;
        if(charStr.includes(character)){
            character = character.charCodeAt(0);
        }else{
            character = character.charCodeAt(0);
        }
        
        var url = Laya.URL.formatURL(prefix+character+".png");
        var texture = map[url];
        return texture;
    };

    /**
     * @method _getLineHeight
     * @param {SpriteSheet} prefix
     * @return {Number}
     * @protected
     **/
    _getLineHeight(prefix) {
        var frame = this._getFrame("1", prefix) || this._getFrame("T", prefix) || this._getFrame("L", prefix);
        return frame ? frame.height : 1;
    };
    /**
     * @method _getSpaceWidth
     * @param {SpriteSheet} prefix
     * @return {Number}
     * @protected
     **/
    _getSpaceWidth(prefix) {
        var frame = this._getFrame("1", prefix) || this._getFrame("l", prefix) || this._getFrame("e", prefix) || this._getFrame("a", prefix);
        return frame ? frame.width : 1;
    };

    // private methods:
    /**
     * @method _cloneProps
     * @param {BitmapText} o
     * @return {BitmapText} o
     * @protected
     **/
    _cloneProps(o) {
        o.lineHeight = this.lineHeight;
        o.letterSpacing = this.letterSpacing;
        o.spaceWidth = this.spaceWidth;
        return o;
    };

    // public methods:
    /**
     * Docced in superclass.
     **/
    render(ctx, x, y) {
        this._updateText();
        super.render(ctx, x, y);
    };

    /**
     * Docced in superclass.
     **/
    getBounds() {
        this._updateText();
        return super.getBounds();
    };

    /**
     * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
     * This does not account for whether it would be visible within the boundaries of the stage.
     * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
     * @method isVisible
     * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
     **/
    isVisible() {
        var hasContent = this.cacheCanvas || (this.text);
        return !!(this.visible && this.alpha > 0 && this.scaleX !== 0 && this.scaleY !== 0 && hasContent);
    };

    clone() {
        return this._cloneProps(new BitmapText(this.text, this.prefix));
    };

}


/**
 * <strong>REMOVED</strong>. Removed in favor of using `MySuperClass_constructor`.
 * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
 * for details.
 *
 * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
 *
 * @method initialize
 * @protected
 * @deprecated
 */
// p.initialize = function() {}; // searchable for devs wondering where it is.

// static properties:
/**
 * BitmapText uses Sprite instances to draw text. To reduce the creation and destruction of instances (and thus garbage collection), it maintains
 * an internal object pool of sprite instances to reuse. Increasing this value can cause more sprites to be
 * retained, slightly increasing memory use, but reducing instantiation.
 * @property maxPoolSize
 * @type Number
 * @static
 * @default 100
 **/
BitmapText.maxPoolSize = 100;

/**
 * Sprite object pool.
 * @type {Array}
 * @static
 * @private
 */
BitmapText._spritePool = [];



